package org.ceteca.explica.client.gui.common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;

import org.apache.log4j.Logger;
import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.ExplicaDetailEntityView;
import org.ceteca.explica.client.gui.ExplicaEntityView;
import org.ceteca.explica.client.gui.ExplicaEventListener;
import org.ceteca.explica.client.gui.ExplicaExtensionFieldsView;
import org.ceteca.explica.client.gui.ExplicaGUIBuilder;
import org.ceteca.explica.client.gui.ExplicaEditEntityView;
import org.ceteca.explica.client.gui.ExplicaEntitySelectionView;
import org.ceteca.explica.client.traceability.gui.TraceabilityTreeView;
import org.ceteca.explica.core.ExplicaException;
import org.ceteca.explica.core.InterfaceErrors;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.common.BaseVO;
import org.ceteca.explica.core.common.CommonManager;
import org.ceteca.explica.core.common.MultiSelectionSubentityOT;
import org.ceteca.explica.core.common.RegistryOT;
import org.ceteca.explica.core.common.SelectionSubentityOT;
import org.ceteca.explica.core.extTables.ExtFieldOT;
import org.ceteca.explica.core.extTables.ExtTableException;
import org.ceteca.explica.core.installer.EntityLauncher;
import org.ceteca.explica.core.installer.EntityLauncherFactory;
import org.ceteca.explica.core.installer.FieldOT;
import org.ceteca.explica.core.installer.SubentityOT;
import org.ceteca.explica.core.partners.InterfacePartners;
import org.ceteca.explica.core.traceability.InterfaceTraceabilityTree;
import org.ceteca.explica.core.util.OperationResult;
import org.ceteca.explica.core.util.ReflectionUtils;
import org.ceteca.explica.core.util.ResultMessage;
import org.ceteca.explica.core.util.SortUtils;
import org.ceteca.explica.core.warehouse.InterfaceWarehouse;
import org.ceteca.javaglade.Gui;
import org.ceteca.javaglade.InterfaceGladeGtk;
import org.ceteca.javaglade.JavaGlade;
import org.ceteca.javaglade.JavaGladeUtil;
import org.ceteca.javaglade.toolkit.swt.SwtDialog;
import org.ceteca.javaglade.toolkit.swt.SwtTopLevelWindow;
import org.ceteca.javaglade.toolkit.swt.SwtWidget;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.hibernate.exception.ConstraintViolationException;

/**
 * @author Juan C. Díaz (juancarlosdiaz@ceteca.net) <br>
 *         Copyright (c) 2009 Fundación Centro Tecnolóxico da Carne
 * 
 * <br>
 * <br>
 *         This program is free software: you can redistribute it and/or modify
 *         it under the terms of the GNU General Public License as published by
 *         the Free Software Foundation, either version 3 of the License, or (at
 *         your option) any later version. <br/>
 *         This program is distributed in the hope that it will be useful, but
 *         WITHOUT ANY WARRANTY 
 *         <br>without even the implied warranty of
 *         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *         General Public License for more details. <br/>
 *         You should have received a copy of the GNU General Public License
 *         along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
public abstract class CommonClient extends EntityLauncher {

//	protected BaseVO selectedEntity = null;
	protected Class<?> classEntity = null;
	protected String editGladePath = null;
	protected String dialogName = null;

//	protected ExplicaEntitySelectionView entSelView;
//	protected ExplicaEditEntityView editEntityView;
//	protected ExplicaEntityView entityDetailView;
//	protected ExplicaEntityView entityView;
	protected ExplicaExtensionFieldsView extFieldsView;

	protected Set<SelectionSubentityOT> lSelectionSubentities = new HashSet<SelectionSubentityOT>();
	protected Set<MultiSelectionSubentityOT> lMultiSelectionSubentities = new HashSet<MultiSelectionSubentityOT>();

	/**
	 * Default constructor
	 * 
	 * @param classEntity
	 *            Class (POJO) of the entity for which the client is built
	 * @param editGlade
	 *            Glade file name
	 * @param dialogN
	 *            Dialog name inside the glade file
	 */
	public CommonClient(Class<?> classEntity, String editGlade, String dialogN) {
		super();
		this.classEntity = classEntity;
		setEditGladePath(editGlade);
		setDialogName(dialogN);
		this.lRegistries = new ArrayList<BaseVO>();

	}

	public CommonClient() {
		super();
		fireExceptionAndExit("Se debe de usar el contructor con parametros");
	}

	@Override
	public ExplicaEntityView buildEntity() {
/*		this.entityDetailView = null;
		if (!this.entityReady || this.entityData == null) {
			if (this.logger != null)
				logger.error(ERROR_START_ENTITY);
			else
				ClientContext.getInstance().getLogger().error(
						ERROR_START_ENTITY);
		} else {
			this.logger.debug(String.format(ENTITY_START, this.entityData
					.getName()));
			// If is the first time the entity is accessed then build the entity
			// view
			if (this.entityView == null || this.entityPanel == null) {
				this.logger.debug("Building the entity panel: "
						+ this.entityData.getName());
				this.entityView = new ExplicaEntityView(
						this.parentGuiName, this.logger, this.entityData, this);
				this.entityPanel = this.entityView.buildEntityView();
			}

			// If any error has taken place during entity view construction
			if (this.entityPanel == null) {
				if (this.logger != null)
					this.logger.error(ERROR_BUILD_ENTITY_PANEL);
				else
					ClientContext.getInstance().getLogger().error(
							ERROR_BUILD_ENTITY_PANEL);
			}

			// Get the parent panel where the entity content is embedded
			Composite parent = (Composite) this.entityView.getParentPanel();
			this.logger.debug("Entity parent panel found: " + parent + " ["
					+ parent.getLayout() + "]");

			// Set up the corresponding entity view as the showed control of the
			// stack.
			// If the entity is part of an entity selection window then the
			// parent control
			// is not a stack layout but a fill layout.
			if (parent.getLayout() instanceof StackLayout)
				((StackLayout) parent.getLayout()).topControl = (Control) this.entityPanel;

			parent.layout(true);
		}

		return null;
*/
		return super.buildEntity();
	}

	@Override
	public ArrayList<ResultMessage> addEntity() {
		ArrayList<ResultMessage> result = new ArrayList<ResultMessage>();
		
		this.logger.info(String.format("Adding new entity..."));
		
		SwtDialog dialog = this.getEntityDialog();
		if (dialog == null) {
			this.logger.error("Error getting entity dialog");
			result.add(new ResultMessage(OperationResult.RESULT_ERROR));
			return result;
		}
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));
		
		this.selectedEntity = null;

		// Clear the form fields
		this.clearEntityData();
		this.logger.info(String.format("Entity selected registry data cleared: %s", this.entityData.getName()));
				
		// Enable the entity edition widgets
		this.setEditionMode(true);
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		return result;
	}

	@Override
	protected void buildEntityDialog() {
		// Show the waiting cursor while the building entity dialog operation takes places.
		Display display = ExplicaGUIBuilder.getInstance().getDisplay();
//		String gladeName = InterfaceExplica.EXPLICA_CORE_GLADE_NAME;
//		this.logger.debug("Entity view name:" + gladeName);
		Shell shell = this.parentGui.getParentWindow().getShell();
		final Cursor cursorWait = new Cursor(display, SWT.CURSOR_WAIT);
		final Cursor oldCursor = shell.getCursor();
		shell.setCursor(cursorWait);
		
		// Build the edit entity view
		String editGuiName = this.parentGui != null?this.getEntityEditViewName(this.parentGui.getGuiName()):this.entityEditGuiName;
		this.entEditView = new ExplicaEditEntityView(this, this.logger, editGuiName, this.parentGui, this.dialogName); 
		this.entEditView.buildExplicaEditEntityView(this.editGladePath);
		
		// Keep the reference of the edit entity dialog
		SwtDialog d = this.entEditView.getDialog();
		this.setEntityDialog(d);

		// Connect the entity edition buttons to their handlers
		this.connectEditEntityButtons();

		// Keep the references to the widgets of the entity edition view
		this.getWidgets();

		// Configure the subentity selection buttons
		this.buildSelectionSets();

		// Configure the subentity multiselection views
		this.buildSubentityMultiSelection();

		// Connect the subentity buttons to their handlers 
		this.connectSubentityButtons();

		// Build the extension view of the entity
		this.build_extension_fields_view();
		
		// Call the specific initation operations needed for the entity
		this.init_specific_components();

		shell.setCursor(oldCursor);
	}

	/* 
	 * Debe de ser sobrescrito en el cliente especifico cuando éste
	 * sea la parte inversa de una relacion one-to-many para poner 
	 * el valor del campo que contiene la clave de la relacion al valor 
	 * del padre cuando se esta creando en una vista de multiseleccion
	 * (Por ejemplo debe de ser sobreescrito en PriceListLineClient para
	 * que ponga el valor adecuado en el campo "lista de precios" cuando
	 * se crea una nueva linea desde el dialogo de edicion de listas de
	 * precios
	 * 
	 */
	@Override
	public void clearEntityData() {
		BaseVO o = null;
		try {
			o = (BaseVO) getClassEntity().newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
			System.exit(-1);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		setWidgetsValues(o);
	}

	@Override
	public ArrayList queryEntity() {
		this.lRegistries = this.queryEntity(null, null);
		return this.lRegistries;
	}

	/**
	 * Search entities not associated with a parent entity (null parent field)
	 * 
	 * 
	 * @param mSubE
	 *            SubentityOT for the parent entity that must be null
	 * @return ArrayList. List of entities found
	 */
	public ArrayList queryFreeEntities(MultiSelectionSubentityOT mSubE) {
		this.lRegistries = null;

		try {
			CommonManager manager = this.getRemote();
			String sql;
			if (mSubE.getParentFieldId() != null
					&& mSubE.getParentFieldId() != null && mSubE.getParentFieldId().length() > 0)
				sql = "from "
						+ ReflectionUtils.getClassShortName(getClassEntity())
						+ " c where c." + mSubE.getParentFieldId() + " is null";
			else
				sql = "from "
						+ ReflectionUtils.getClassShortName(getClassEntity())
						+ " c";
			
			ArrayList<BaseVO> lRegs = (ArrayList) manager.queryEntities(sql);
			if (this.lRegistries != null)
				this.lRegistries.clear();
			else
				this.lRegistries = new ArrayList<BaseVO>();
			
			// Remove the subentitis already selected for the master entity
			for (BaseVO ent : lRegs) {
				if (!mSubE.getSubentityLauncher().getLRegistries().contains(ent)) {
					this.lRegistries.add(ent);
				}
			}
		} catch (AccessException aEx) {
			aEx.printStackTrace();
		} catch (RemoteException rEx) {
			rEx.printStackTrace();
		} catch (ExplicaException eEx) {
			eEx.printStackTrace();
		}
		return this.lRegistries;
	}

	@Override
	public ArrayList queryEntity(String fieldId, String value) {
		this.lRegistries = null;
		
		try {
			CommonManager manager = this.getRemote();
			
			// If the query is made by a detail field get the value of the detail entity
			FieldOT field = this.entityData.getField(fieldId); 
			if (field != null && !field.getDetailEntity().isEmpty() && !field.getDetailField().isEmpty()) {
				// Get the class of the detail entity
				
				Class detailClass = this.classEntity.getDeclaredField(field.getDetailEntity()).getType();
				BaseVO detailValue = manager.getEntity(field.getDetailField(), value, detailClass);
				this.lRegistries = (ArrayList) manager.queryEntities(field.getDetailEntity(),
						detailValue, this.classEntity);
			}
			else {
				this.lRegistries = (ArrayList) manager.queryEntities(fieldId,
						value, this.classEntity);
			}
		} catch (AccessException aEx) {
			aEx.printStackTrace();
		} catch (RemoteException rEx) {
			rEx.printStackTrace();
		} catch (ExplicaException eEx) {
			eEx.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
		return this.lRegistries;
	}

	/**
	 * 
	 * Get access to the server via rmi
	 * 
	 * @return CommonManager. An instance of CommonManager used to invoke
	 *         operations on the server
	 * @throws ExplicaException
	 */
	protected CommonManager getRemote() throws ExplicaException {

		try {

			Registry registry = LocateRegistry
					.getRegistry(InterfaceExplica.RMI_REGISTRY_PORT);

			CommonManager manager = (CommonManager) registry
					.lookup(InterfaceExplica.JNDI_COMMON_MANAGER_EXPORT_NAME);

			return manager;
		} catch (AccessException aEx) {
			aEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_NO_ACCESS,
									aEx,
									(Object) InterfaceExplica.JNDI_COMMON_MANAGER_EXPORT_NAME,
									(Object) null));
		} catch (NotBoundException nEx) {
			nEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_NOT_BOUND,
									nEx,
									(Object) InterfaceExplica.JNDI_COMMON_MANAGER_EXPORT_NAME,
									(Object) null));
		} catch (RemoteException rEx) {
			rEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND,
									rEx,
									(Object) InterfaceExplica.JNDI_COMMON_MANAGER_EXPORT_NAME,
									(Object) null));
		}
	}

	@Override
	public OperationResult delEntity() {
		return null;
	}

	@Override
	public OperationResult editEntity() {
		OperationResult result = new OperationResult();
		if (selectedEntity == null)
			return result;
		
		this.logger.info(String.format("Editing entity: %s (%d)", this.entityData.getName(), this.getSelectedId()));

		SwtDialog dialog = this.getEntityDialog();
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));
		
		if (dialog == null) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_EDIT_ENTITY));
			return result;
		}

		// Fill the form fields with the edited product data
		this.fillEntityData();
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));

		// Enable the entity edition widgets
		this.setEditionMode(true);
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		return result;
	}

	@Override
	public ArrayList getEntityFields() {
		return null;
	}
/*
	@Override
	public BaseVO getSelectedEntity() {
		return this.selectedEntity;
	}

	@Override
	public Long getSelectedId() {
		return (this.selectedEntity == null ? null : this.selectedEntity
				.getInternalId());
	}
*/
	@Override
	public OperationResult printEntity() {
		OperationResult result = new OperationResult();
		String reportPath = InterfacePartners.EXPLICA_PARTNERS_GENERIC_REPORT;
		
		result.add(printEntity(reportPath, null));
		return result;

	}

	public OperationResult printEntity(String reportPath, HashMap<String, Object> parameters) {
		OperationResult result = new OperationResult();
		URL url = this.getClass().getResource(reportPath);
		if (url == null) {

			ArrayList<String> lParams=new ArrayList<String>();
			lParams.add(reportPath);


			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_JASPER_FILE_NOT_FOUND, lParams) );
			return result;
		}
		ArrayList<BaseVO> list = new ArrayList<BaseVO>();
		for (BaseVO b : getRegistries())
			list.add(b);
		try {
			JasperPrint jp = JasperFillManager.fillReport(this.getClass()
					.getResourceAsStream(reportPath), parameters,
					new JRBeanCollectionDataSource(list));
			
			JasperViewer.viewReport(jp, false);
			result.addResultMessage(OperationResult.RESULT_OK,
					new ResultMessage(InterfaceErrors.MSG_REPORT_OK));
		} catch (JRException e) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_JASPERREPORTS_EXCEPTION, e));
			e.printStackTrace();
		}

		return result;
	}
	
	@Override
	public ArrayList<RegistryOT> queryEntityWithFormat(String fieldId,
			String value) {
		ArrayList<RegistryOT> result = new ArrayList<RegistryOT>();
		this.lRegistries = this.queryEntity(fieldId, value);
		if (lRegistries != null && !lRegistries.isEmpty())
			SortUtils.sortLBaseVO(lRegistries);
		for (int i = 0; this.lRegistries != null && i < this.lRegistries.size(); i++) {
			BaseVO dep = (BaseVO) lRegistries.get(i);
			String[] lValues = dep.format(this.entityData.getIdField(),
					this.entityData.getLFields());
			RegistryOT reg = new RegistryOT(dep.getInternalId(),
					"id", lValues);
			result.add(reg);
		}
		return result;
	}

	@Override
	public void selectEntity(Long idEntity) {
		if (idEntity == null) {
			this.logger.error("You can not select null index");
			System.exit(-1);
		}
		if (this.lRegistries != null && this.lRegistries.size() > 0) {
			int index = this.indexOf(idEntity);

			if (index >= 0) {
				this.selectedEntity = (BaseVO) this.lRegistries.get(index);

			} else
				this.selectedEntity = null;
		}
		selectTreeItem(idEntity);
	}

	@Override
	public void updateEntityData() {

	}

	@Override
	public OperationResult viewEntity() {
		OperationResult result = new OperationResult();
		
		if (selectedEntity == null)
			return result;
		
		this.logger.info(String.format("Viewing entity: %s (%d)", this.entityData.getName(), this.getSelectedId()));
		SwtDialog dialog = this.getEntityDialog();
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));
		if (dialog == null) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_EDIT_ENTITY));
			return result;
		}

		// Fill the form fields with the edited product data
		this.fillEntityData();
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));
		
		// Disable the entity edition widgets
		this.setEditionMode(false);
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		result.addResultMessage(OperationResult.RESULT_OK, ClientContext
				.getInstance().getMsgCatalog().newResultMessage(
						InterfaceErrors.MSG_EDIT_ENTITY_OK));

		return result;
	}

	public String getEditGladePath() {
		return editGladePath;
	}

	public void setEditGladePath(String editGladePath) {
		this.editGladePath = editGladePath;
	}

	public String getDialogName() {
		return dialogName;
	}

	public void setDialogName(String dialogName) {
		this.dialogName = dialogName;
	}

	@Override
	public OperationResult saveEntity() {
		OperationResult result = new OperationResult();

		OperationResult resultValidation = validateEntity();
		if (resultValidation != null)
			if (resultValidation.getResult() != OperationResult.RESULT_OK) {
				return resultValidation;
			}

		BaseVO entity = getEntityData();

		this.logger.debug("Saving entity:" + entity.toString());

		if (entity == null) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_SAVE_ENTITY_NULL));
			ExplicaGUIBuilder.getInstance().showConfirmationDialog(
					this.entEditView.getGui().getParentWindow().getShell(),
					"Error grabando null entity", "ERROR", SWT.ICON_ERROR,
					SWT.OK);
			return result;
		}

		result.add(saveEntity(entity));

		if (result.getResult() == OperationResult.RESULT_OK) {
			if (extFieldsView != null)
				result.add(this
						.saveEntityExtensionTable(entity.getInternalId()));
		}
		else {
			result.getResultMessagesList().get(0).getExc().printStackTrace();
		}

		if (result.getResult() == OperationResult.RESULT_OK) {

			BaseVO newEntity = this.refreshEntity(entity);
			if (newEntity == null)
				fireExceptionAndExit("Error. Cant not refresh entity");
			this.updateRegistry(newEntity);
			this.updateViews(false);
		}
		
		return result;
	}

	/**Delete a set of subentities from record list of controller, not from database
	 * <br>
	 * Set the parent field of subentity to null
	 * <br>
	 * 
	 * @param selRegistries
	 * List of  index to delete
	 * @return
	 * OperationResult. Result of the operation
	 */

	public OperationResult delSubentities(ArrayList<Long> selRegistries) {

		OperationResult result = new OperationResult();

		if (!isDetail() || selRegistries == null)
			return result;
		if (selRegistries.isEmpty())
			return result;

		String parentField = entityDetailView.getSubentityData()
				.getParentFieldId();


		ArrayList<BaseVO> toRemove = new ArrayList<BaseVO>();
		for (BaseVO r : lRegistries) {
			if (selRegistries.contains(r.getInternalId())) {
				toRemove.add(r);
			}
		}
		
		
		CommonManager manager = null;
		try {
			manager = this.getRemote();
		} catch (ExplicaException e1) {
			e1.printStackTrace();
			result.addResultMessage(OperationResult.RESULT_ERROR,
					new ResultMessage(OperationResult.RESULT_ERROR, e1
							.getCause()));

		}
		if (parentField != null) {
			for (BaseVO r : toRemove) {
				
				
				// Aqui debemos de poner el campo que referencia la entidad
				// principal a null
				// para desligarla de la entidad principal

				// ReflectionUtils utils = new ReflectionUtils();
				Method method = ReflectionUtils.getSetter(getClassEntity(),
						parentField);
				if (method == null) {
					result
							.addResultMessage(
									OperationResult.RESULT_ERROR,
									ClientContext
											.getInstance()
											.getMsgCatalog()
											.newResultMessage(
													InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND));
					return result;
				}

				this.logger
						.debug("Setter name to remove subentity master entity reference="
								+ method.getName());
				try {
					method.invoke(r, (Object) null);
					if (manager != null)
						result = manager.saveEntity(r);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR,
							new ResultMessage(OperationResult.RESULT_ERROR, e
									.getCause()));

				} catch (IllegalAccessException e) {
					e.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR,
							new ResultMessage(OperationResult.RESULT_ERROR, e
									.getCause()));
				} catch (InvocationTargetException e) {
					e.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR,
							new ResultMessage(OperationResult.RESULT_ERROR, e
									.getCause()));
				} catch (ExplicaException e) {
					e.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR,
							new ResultMessage(OperationResult.RESULT_ERROR, e
									.getCause()));

				} catch (RemoteException e) {
					e.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR,
							new ResultMessage(OperationResult.RESULT_ERROR, e
									.getCause()));
				}
			}
		}

		lRegistries.removeAll(toRemove);
		this.entityDetailView.fillEntityTable(formatRegistries(lRegistries));
		result.addResultMessage(OperationResult.RESULT_OK, ClientContext
				.getInstance().getMsgCatalog().newResultMessage(
						InterfaceErrors.MSG_DELETE_ENTITY_OK));
		return result;

	}

	@Override
	public OperationResult delEntity(ArrayList<Long> selRegistries) {
		OperationResult result = new OperationResult();
		
		if (selRegistries == null)
			return result;
		this.logger.debug(String.format("Deleting %s entities ", selRegistries
				.size()));
		if (selRegistries.isEmpty())
			return result;
		
		// Show the confirmation dialog and get the user response
		if (this.confirmEntityDelete()) {
			if (isDetail()) {
				result.add(removeRegistries(selRegistries, this.entityDetailView
						.getSubentityData().getParentFieldId()));
//				result.add(refreshParentSelectedEntity());
			} // if es detalle
			else {
				try {
					CommonManager manager = this.getRemote();
					for (Long i : selRegistries) {
						result.add(manager.delEntity(getRegistry(i)));
					} // for each selected registry
				} catch (RemoteException rEx) {
					result
							.addResultMessage(
									OperationResult.RESULT_ERROR,
									ClientContext
											.getInstance()
											.getMsgCatalog()
											.newResultMessage(
													InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND,
													rEx));
				} catch (ExplicaException eEx) {
					eEx.printStackTrace();
					result.addResultMessage(OperationResult.RESULT_ERROR, eEx
							.getResMsg());

				} catch (IllegalArgumentException rEx) {
					result
							.addResultMessage(
									OperationResult.RESULT_ERROR,
									ClientContext
											.getInstance()
											.getMsgCatalog()
											.newResultMessage(
													InterfaceErrors.ERR_DELETE_ENTITY,
													rEx));
				} // try-catch
			} // else no es detalle
		} // if borrado confirmado
		else {
			this.logger.info(String.format("Entity delete cancelled: (%s - %d)!", this.entityData.getName(), this.getSelectedId()));
			result = new OperationResult();
			ArrayList lParams = new ArrayList();
			lParams.add(this.entityData.getName());
			lParams.add(this.getSelectedId());
			result.addResultMessage(OperationResult.RESULT_WARNING, ClientContext.getInstance().getMsgCatalog().newResultMessage(InterfaceErrors.MSG_DELETE_ENTITY_CANCELLED, lParams));
		} // else borrado cancelado
		
		if (result.getResult() == OperationResult.RESULT_OK) {
			updateViews(!isDetail());
		} 
		else if (!(this.entView instanceof ExplicaEntityView))
			showErrorMessages(result);

		return result;

	}

	public void showErrorMessages(OperationResult result) {
		OperationResult localizedResult = ClientContext.getInstance()
				.localizeOperationResult(result);

		ExplicaGUIBuilder.getInstance().showConfirmationDialog(
				this.entView.getGui().getParentWindow().getShell(),
				localizedResult.getFormattedResult(), "ERROR", SWT.ICON_ERROR,
				SWT.OK);

	}

	public BaseVO refreshEntity(BaseVO entity) {
		this.logger.debug("Refreshing entity: " + entity);
		BaseVO result = null;
		try {
			if (entity.getInternalId() != 0) {
				result = this.loadEntity(entity.getInternalId());
			} else {
				this.logger.debug("Refrescando nueva entidad");
				List<BaseVO> entities = this.loadEntities();
				this.logger.debug("Resultados de la busqueda");

				for (BaseVO b : entities) {
					this.logger.debug(b);
					if (b.equals(entity)) {
						result = b;
						this.logger.debug("encontrado");
					} else
						this.logger.debug("No es igual");
				}
			}
		} catch (ExplicaException e) {
			e.printStackTrace();
		}

		return result;
	}

	public OperationResult refreshEntity() {
		OperationResult result = new OperationResult();
		if (selectedEntity == null)
			return result;
		long id = selectedEntity.getInternalId();
		
		lRegistries.remove(selectedEntity);
		try {
			// this.logger.debug(selectedEntity.toString());
			this.logger.debug("Entity before reload "
					+ selectedEntity.toString());
			selectedEntity = this.loadEntity(id);
			this.logger.debug("Entity after reload "
					+ selectedEntity.toString());
			// this.logger.debug(selectedEntity.toString());
			lRegistries.add(selectedEntity);
			// SortUtils.sortLBaseVO(lRegistries);
		} 
		catch (ExplicaException e) {
			result.addResultMessage(OperationResult.RESULT_ERROR,
					new ResultMessage(OperationResult.RESULT_ERROR, e
							.getCause()));
		}
		return result;
	}

	public void addTrazabilityTree(TabFolder tabFolder) {
		try {
			// Create a new tab for embedding the traceability tree viewer
			TabItem trViewerTab = (TabItem)ExplicaGUIBuilder.getInstance().getToolkit().
					tabItem(tabFolder, "productTrViewerTab");
			ExplicaGUIBuilder.getInstance().getToolkit().setTabItemLabel(trViewerTab, ClientContext.getInstance().getI18n().tr("Traceability"));
			this.entEditView.getGui().addWidget("trViewerTab_" + this.entityData.getName(),
					trViewerTab,
					InterfaceWarehouse.EDIT_PRODUCT_NOTEBOOK_WIDGETNAME);
			
			Composite trViewerPanel = (Composite)ExplicaGUIBuilder.getInstance().getToolkit().
					emptyPanel(trViewerTab.getParent(), "productTrViewerPanel");
			ExplicaGUIBuilder.getInstance().getToolkit().addTabItemContent(trViewerTab, trViewerPanel);
			trViewerPanel.setLayout(new FillLayout());
			this.entEditView.getGui().addWidget("trViewerPanel_" + this.entityData.getName(),
					trViewerPanel,
					"trViewerTab_" + this.entityData.getName());
			
			TraceabilityTreeView treeView = TraceabilityTreeView.getInstance();
			
			this.logger.info("Building traceability tree viewer: " + this.getClass().getResource(InterfaceTraceabilityTree.TREEVIEWER_GLADE_FILE).getPath());
			treeView.buildTreeView(InterfaceTraceabilityTree.TREEVIEWER_GLADE_FILE, 
					this.entEditView.getGui().getSwtWidget("trViewerPanel_" + this.entityData.getName()),
					this.entEditView.getGui());
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public ExplicaEntityView buildEntityDetail(
			MultiSelectionSubentityOT subentityData) {

		this.entView = null;

		if (this.entityData == null) {
			if (logger != null)
				logger.error(ERROR_START_ENTITY);
			else
				ClientContext.getInstance().getLogger().error(
						ERROR_START_ENTITY);
		} else {
			this.entityDetailView = this.buildEntity(subentityData.getPanel(), subentityData, subentityData.getParentFieldId());
			this.fillEntityTable();

			// Composite entPanel = (Composite)
			// entityDetailView.getEntityPanel();
			if (entityPanel.getLayout() instanceof StackLayout)
				((StackLayout) entityPanel.getLayout()).topControl = (Control) this.entityPanel;
			entityPanel.layout(true);
		}

		return this.entityDetailView;
	}

	public Logger getLogger() {
		return this.logger;
	}

	@Override
	public void fillEntityData() {
		if (this.entEditView != null)
			this.entEditView.updateView();
	}

	public void buildSubentityMultiSelection() {

		for (MultiSelectionSubentityOT subE : this.lMultiSelectionSubentities) {
			// Get the entity launcher factory for creating a new entity launcher
			// that will handle the entity events.
			EntityLauncherFactory factory = this.getEntityLauncherFactory(subE.getSubentityData());
			
			// Get the entity launcher instance that will handle the entity events
			EntityLauncher entLauncher = factory.getEntityLauncher(subE.getPanel());
			if (entLauncher == null) {
				fireExceptionAndExit("Fatal error: null entity launcher: "+subE.getSubentityData().getName());
			}
			entLauncher.initEntityLauncher(this.logger, this.entEditView.getGui(), subE.getPanel());
			subE.setSubentityLauncher(entLauncher);
			
			Composite panel = subE.getPanelWidget();
			if (panel == null) {
				fireExceptionAndExit("Fatal error: null panel");
			}
			panel.setLayout(new FillLayout());
			
			ExplicaDetailEntityView subentView = entLauncher.buildEntity(subE.getPanel(), subE, subE.getSubentityWidgetName());
			this.entEditView.addMultiSelection(subE, subentView);
		}
	}

/*	@Override
	final public void on_entityEditionCancelButton_clicked(Event e) {
		System.out.println("Forbidden method");
		this.logger.fatal("Forbidden method");
		System.exit(-1);
	}

	@Override
	final public void on_entityEditionSaveButton_clicked(Event e) {
		System.out.println("Forbidden method");
		this.logger.fatal("Forbidden method");
		System.exit(-1);
	}

	@Override
	final public void on_entityEditionUndoButton_clicked(Event e) {
		System.out.println("Forbidden method");
		this.logger.fatal("Forbidden method");
		System.exit(-1);
	}
*/
/*
	@Override
	protected final void connectEditEntityButtons() {
		super.connectEditEntityButtons();
		System.out.println("Forbidden method");
		logger.fatal("Forbidden method");
		System.exit(-1);
	}
*/

	/**
	 * Fill the entity view table with the records given
	 * 
	 * @param lR
	 *            ArrayList. Records to be displayed
	 */
	public void fillEntityTable(ArrayList<RegistryOT> lR) {
		getView().fillEntityTable(lR);
	}

	/**
	 * Load records from database and fill the entity view table and controller
	 * record list
	 */
	public void fillEntityTable() {
		getView().fillEntityTable(formatRegistries());
	}

	/**
	 * Getter for parentGuiName
	 */
/*	public String getParentGuiName() {
		return parentGuiName;
	}
*/

	/**
	 * Getter for lRegistries
	 */
/*	public ArrayList<BaseVO> getLRegistries() {
		return lRegistries;
	}
*/

	/**
	 * Select a item in the entity tree. No me gusta esto aqui
	 * 
	 * @param id
	 *            Long. Index of item to select
	 */
	public void selectTreeItem(Long id) {
		if (id == null)
			return;
		
		Tree tree = getView().getEntityTreeWidget();

		if (tree != null)
			for (TreeItem item : tree.getItems()) {
				Long idItem = new Long(item.getText(0));
				if (idItem != null)
					if (id.longValue() == idItem.longValue())
						tree.select(item);
			}
	}

	/**
	 * Shows a dialog for selection of a new subentity
	 * 
	 * @param ent
	 *            SubentityOT. Encapsulate data type of subentity
	 */
	public void addExistingSubentity(SubentityOT ent) {
		this.logger.info("Select an existing subentity clicked: " + this.getClass());
		if (isDetail()) {
			if (this.entSelView == null)
				fireExceptionAndExit("Error. I cant not build the dialog");
	
			entSelView.showSubentitySelection(ent);
		}
	}

	/**
	 * Build view of selection entities
	 * 
	 * @return ExplicaPartnerSelectionView. SelectionView created
	 */
	public ExplicaEntitySelectionView buildEntitySelectionView() {
		if (this.entSelView != null)
			return this.entSelView;
		
		// Create a new instance of the ExplicaEntitySelectionView to manage
		// the events of the product subentity selection buttons
		if (this.entEditView != null) {
			this.entSelView = new ExplicaEntitySelectionView(
				this.entitySelectionGuiName,
				this.entEditView.getGui());
		}
		else {
			this.entSelView = new ExplicaEntitySelectionView(
					this.entitySelectionGuiName,
					this.entityDetailView.getGui());
		}
		this.entSelView.buildSelectionDialog();
		
		return this.entSelView;
	}

	@Override
	protected void connectSubentityButtons() {

		buildEntitySelectionView();

		for (SelectionSubentityOT subentity : lSelectionSubentities) {
			this.logger.debug("Connecting subentity "
					+ subentity.getSubentityData().getName() + " to Widget: "
					+ subentity.getParentFieldId());
			ExplicaGUIBuilder
					.getInstance()
					.connectSignal(
							InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED,
							subentity.getButton(),
							InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_CLICKED_HANDLER,
							entSelView);
			subentity.getButton().setData(subentity);

		}

	}

	/**
	 * Adds a existent entity to a multiselection list
	 * 
	 * @param subentity
	 *            Subentity to be added
	 * @param subE
	 *            Object that encapsulates information about the subentity
	 */
	public void addSubentity(BaseVO subentity, MultiSelectionSubentityOT subE) {

		if (!isDetail())
			fireExceptionAndExit("Adding subentity on a entity launcher no detail");

		if (subentity == null) {
			this.logger.info("Selected subentity null");
			return;
		}

		if (subE == null) {
			this.logger.info("SubEntity Type null");
			return;
		}

		if (getParentEntityLauncher() == null)
			fireExceptionAndExit("Error. Null parent entity launcher on subentity multiselection");

		if (getParentEntityLauncher().getSelectedEntity() == null)
			fireExceptionAndExit("Error. Null selection entity adding subentity");

		// Link the subentity with the parent entity setting
		// the parent field value
		if (subE.getParentFieldId() != null
				&& subE.getParentFieldId() != null && subE.getParentFieldId().length() > 0) {
			BaseVO parentEntity = this.getParentEntityLauncher()
					.getSelectedEntity();

			// Change the parent field value Method setParent =
			Method setParent = ReflectionUtils.getSetter(subentity.getClass(),
					subE.getParentFieldId());
			this.logger.debug("Setter Method of field "
					+ subE.getParentFieldId() + " for class: "
					+ subentity.getClass() + " --> " + setParent);
			try {
				setParent.invoke(subentity, parentEntity);
			} catch (IllegalArgumentException e) {
				fireExceptionAndExit("Error setting parent field");
			} catch (IllegalAccessException e) {
				fireExceptionAndExit("Error setting parent field");
			} catch (InvocationTargetException e) {
				fireExceptionAndExit("Error setting parent field");
			}

		}

		this.logger.debug("Adding subentity: " + subentity);
		this.updateRegistry(subentity);
		this.updateViews(false);

	}

	@Override
	public void selectSubentity(String parentFieldId, BaseVO subentityOT) {

		if (parentFieldId != null && parentFieldId.length() > 0
				&& subentityOT != null) {
			this.logger.debug(String.format(
					"Setting up a new value for the field %s: %s",
					parentFieldId, subentityOT));
			try {
				this.logger.debug(String.format(
						"Searching the parent widget: %s --> %s",
						parentFieldId, this.entEditView.getGui()
								));
				// ExplicaGUIBuilder.getInstance().printGUIs(this.logger);
				Widget widget = this.getWidget(parentFieldId);
				if (widget == null)

					fireExceptionAndExit("Cant not get widget for subentity selection");

				widget.setData(subentityOT);
				if (widget instanceof Text) {
					Text entry = (Text) widget;
					entry.setText(subentityOT.getInternalValue());
				}
				else if (widget instanceof StyledText) {
					StyledText entry = (StyledText) widget;
					entry.setText(subentityOT.getInternalValue());
				}
				else {

					this.logger
							.error("Error, Se debe de implementar el codigo final en el el cliente");
				}

			} catch (Exception ex) {
				ex.printStackTrace();
				this.logger
						.error(
								String
										.format(
												"Error updating the selected subentity field %s with the value %s",
												parentFieldId, subentityOT), ex);
			}
		} else {
			this.logger
					.error(String
							.format(
									"Error setting up a new value for a subentity (%s) field! The field name is null or empty!",
									subentityOT == null ? "NULL" : subentityOT
											.getClass().toString()));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.ceteca.explica.core.installer.EntityLauncher#querySubentities(org
	 * .ceteca.explica.core.installer.SubentityOT) Modified to make use of
	 * reflection and not have to be overwritten on each client
	 * 
	 * Modificada para hacer uso de reflection y no tener que ser sobreescrito
	 * en cada cliente
	 */
	@Override
	public ArrayList querySubentities(SubentityOT entData) {

		if (!(entData instanceof MultiSelectionSubentityOT))
			return null;
		MultiSelectionSubentityOT subE = (MultiSelectionSubentityOT) entData;

		ArrayList result = new ArrayList();

		if (entData != null && selectedEntity != null) {
			this.logger.debug("Quering subentities "
					+ entData.getSubentityData().getName() + " key: "
					+ entData.getSubentityData().getKey());

			Method getList = ReflectionUtils.getGetter(getClassEntity(), subE
					.getCollectionName());
			this.logger.debug("Getter method of field "
					+ subE.getCollectionName() + " for class: "
					+ getClassEntity() + " --> " + getList);

			try {
				Collection<BaseVO> col = (Collection<BaseVO>) getList
						.invoke(selectedEntity);
				result = new ArrayList(col);
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		// SortUtils.sortLBaseVO(result);
		return result;
	}

	/**
	 * Setter for lRegistries
	 */
	public void setRegistries(Collection<BaseVO> collection) {
		if (this.lRegistries == null)
			this.lRegistries = new ArrayList<BaseVO>();
		this.lRegistries.clear();
		if (collection != null)
			this.lRegistries.addAll(collection);

	}

	/**
	 * @return lRegistries
	 */
	public Collection<BaseVO> getRegistries() {
		return this.lRegistries;
	}

	/**
	 * Force the update of the views associated
	 * 
	 * @param updateFromParent
	 *            Indicates whether the view must be updated by reading the
	 *            values from the parent entity. takes effect only when the
	 *            entity is detail (is embedded in another)
	 */
	public void updateViews(boolean updateFromParent) {
		SortUtils.sortLBaseVO(lRegistries);
		Long sel = null;
		if (this.getSelectedEntity() != null)
			sel = this.getSelectedId();
		if (this.entEditView != null) {
			this.logger.debug("Updating edit entity view");
			this.entEditView.updateView();
		}
		if (this.entView != null) {
			this.logger.debug("Updating entity view");
			this.entView.showEntityView();
		}
		else if (this.entityDetailView != null) {
			this.logger.debug("Updating detail view");
			if (updateFromParent)
				this.entityDetailView.showEntityView();
			else {
				this.entityDetailView.updateView();

			}
		}
		if (sel != null)
			this.selectEntity(sel);
	}

	/**
	 * Add or update an entity (to the controller records)
	 * 
	 * @param ent
	 *            Entity to add or update
	 */
	public void updateRegistry(BaseVO ent) {
		ArrayList<BaseVO> toRemove = new ArrayList<BaseVO>();
		if (ent == null)
			return;
		if (lRegistries != null) {
			for (BaseVO b : lRegistries)
				if (b.getInternalId() == ent.getInternalId())
					toRemove.add(b);
		}
		else
			lRegistries = new ArrayList<BaseVO>();
		
		lRegistries.removeAll(toRemove);
		lRegistries.add(ent);
	}

	/**
	 * Get a list of entities stored by the controller
	 * 
	 * @param lIds
	 *            Index list
	 * @return List of entities
	 */
	public List<BaseVO> getRegistries(ArrayList<Long> lIds) {
		ArrayList<BaseVO> result = new ArrayList<BaseVO>();
		for (Long i : lIds) {
			BaseVO reg = this.getRegistry(i);
			if (reg != null)
				result.add(reg);
		}
		return result;
	}

	/**
	 * Deletes a list of the records stored by the controller. Also clean your
	 * parent fields and updates the database
	 * 
	 * @param selRegistries
	 *            Index list to remove
	 * @param parentField
	 *            Field name that links to the parent entity
	 * @return OperationResult. Result of the operation
	 */
	public OperationResult removeRegistries(ArrayList<Long> selRegistries,
			String parentField) {
		OperationResult result = new OperationResult();
		try {
			if (selRegistries == null)
				return result;
			if (selRegistries.isEmpty())
				return result;

			ArrayList<BaseVO> toRemove = new ArrayList<BaseVO>();
			for (BaseVO b : lRegistries)
				for (Long i : selRegistries)
					if (b.getInternalId() == i)
						toRemove.add(b);

			this.lRegistries.removeAll(toRemove);
			for (BaseVO b : toRemove) {
				if (parentField != null && parentField.length() > 0) {
					result.add(ReflectionUtils.cancelField(b, parentField));
					result.add(this.saveEntity(b));
				}
			}

		} catch (Exception e) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_DELETE_ENTITY, e));
		}
		if (result.getResult() != OperationResult.RESULT_ERROR)
			result.addResultMessage(OperationResult.RESULT_OK, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.MSG_DELETE_ENTITY_OK));
		return result;

	}

	/**
	 * Clears the value of the field indicated
	 * 
	 * @param selRegistries
	 *            ArrayList. Index list of records to process
	 * @param parentField
	 *            Name of the field to clear
	 * @return OperationResult. Result of operation
	 */
	public OperationResult clearParentField(ArrayList<Long> selRegistries,
			String parentField) {
		OperationResult result = new OperationResult();
		for (Long i : selRegistries) {
			result.add(ReflectionUtils.cancelField(getRegistry(i),
					parentField));
		}
		return result;
	}

	public OperationResult saveEntity(ArrayList<Long> lIds) {
		OperationResult result = new OperationResult();
		for (Long i : lIds) {
			result.add(saveEntity(this.getRegistry(i)));
		}
		return result;
	}

	/**
	 * Save or update a entity to database
	 * 
	 * @param b
	 *            BaseVO. Entity to save or update
	 * @return OperationResult. Result of the operation
	 */
	public OperationResult saveEntity(BaseVO b) {
		OperationResult result = new OperationResult();

		try {
			CommonManager manager = this.getRemote();
			result.add(manager.saveEntity(b));

		} catch (ExplicaException ex) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ex
					.getResMsg());

		} catch (RemoteException rEx) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND, rEx));

		}
		return result;
	}

	/**
	 * Delete a entity from database
	 * 
	 * @param b
	 *            BaseVO. Entity to delete
	 * @return OperationResult. Result of the operation
	 */
	public OperationResult delEntity(BaseVO b) {
		OperationResult result = new OperationResult();

		try {
			CommonManager manager = this.getRemote();
			result.add(manager.delEntity(b));

		} catch (ExplicaException ex) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ex
					.getResMsg());

		} catch (RemoteException rEx) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND, rEx));

		}
		return result;
	}

	/**
	 * Reload from database the value of the parent entity of the selected
	 * entity
	 * 
	 * @return OperationResult. The result of the operation.
	 */
	public OperationResult refreshParentSelectedEntity() {
		OperationResult result = new OperationResult();
		EntityLauncher el = this.entityDetailView.getSubentityData()
				.getParentEntity();
		if (el instanceof CommonClient)
			result.add(((CommonClient) el).refreshEntity());
		return result;
	}

	/**
	 * @return EntityLauncher of parent entity if is a embedded entity or null
	 *         otherwise
	 */
	public EntityLauncher getParentEntityLauncher() {
		if (entityDetailView == null)
			return null;
		EntityLauncher el = this.entityDetailView.getSubentityData()
				.getParentEntity();
		return el;
	}

	
	
	
	public SwtTopLevelWindow getEditWindow() {
		SwtTopLevelWindow result;
		try {
			result = this.entEditView.getGui().getWindow(getDialogName()); 
		} catch (Exception ex) {
			this.logger
					.error(
							"Error setting up the parentWindow of the ExplicaEntitySelection dialog!",
							ex);
			result = null;
		}
		try {
			if (result == null) {
				SwtDialog dialog = this.entEditView.getGui().getDialog(dialogName);
				result = new SwtTopLevelWindow(dialogName, dialog.getShell(), false);
			}
		} catch (Exception ex) {
			this.logger
					.error(
							"Error setting up the parentWindow of the ExplicaEntitySelection dialog!",
							ex);
			result = null;
		}
		return result;

	}

	/**
	 * @return ExplicaEntityView. Main view or Detail view if is a
	 *         embedded entity.
	 */
	public ExplicaEntityView getView() {
		ExplicaEntityView view = null;
		if (isDetail())
			view = this.entityDetailView;
		else
			view = this.entView;
		if (view == null)
			try {
				throw new ExplicaException(
						ClientContext
								.getInstance()
								.getMsgCatalog()
								.newResultMessage(
										InterfaceErrors.ERR_NULL_ENTITY_LAUNCHER_ON_VIEW));
			} catch (ExplicaException e) {

				e.printStackTrace();
				System.exit(-1);
			}
		return view;
	}

	/**
	 * @return
	 * 	Class of the entity for which the controller is built
	 */
	public Class<?> getClassEntity() {
		if (this.entityData == null)
			this.logger.warn("Error. Null entityData field on entitylauncher");
		else if (this.entityData.getClass() == null
				|| this.entityData.getClass() != this.classEntity)
			this.logger
					.warn("Error. classentity!=entityData.getClass() on CommonClient");

		return this.classEntity;
	}

	@Override
	protected Tree getEntityTree() {
		return this.getView().getEntityTreeWidget();

	}

	/**
	 * Retrieve extension field values from the server for a given entity and
	 * displays them in the view
	 * 
	 * @param id
	 *            Long. Key of the entity whose values are to be displayed
	 */
	public void fillEntityExtensionTable(Long id) {

		if (extFieldsView == null)
			return;
		try {

			CommonManager manager = this.getRemote();
			Map<String, ExtFieldOT> m = manager.getExtendedItemValues(id,
					extFieldsView.getExtTable().getCodExtTable());
			extFieldsView.fillExtendedFieldsTree(m);

		} catch (AccessException aEx) {
			this.logger
					.error(
							"Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!",
							aEx);
			aEx.printStackTrace();
		} catch (RemoteException rEx) {
			this.logger
					.error(
							"No se encontró el servicio o hubo errores al llamar a los métodos remotos!",
							rEx);
			rEx.printStackTrace();
		} catch (ExtTableException ex) {
			ex.printStackTrace();
			this.logger
					.error(
							"No se ha podido cargar el catalogo de propiedades de extension para la tabla: "
									+ extFieldsView.getExtTable()
											.getCodExtTable(), ex);
			this.logger.error(ex.getLocalizedMessage());
		} catch (ExplicaException eEx) {
			this.logger
					.error(
							"No se ha podido cargar el catalogo de propiedades de extension para la tabla: "
									+ extFieldsView.getExtTable()
											.getCodExtTable(), eEx);
			eEx.printStackTrace();
		}
	}

	/**	Retrieve fields stored in the Extension Fields view and store it in the database
	 * @param id
	 * Long. Internal id of entity 
	 * @return
	 * OperationResult. Result of operation
	 */
	protected OperationResult saveEntityExtensionTable(Long id) {

		OperationResult result = new OperationResult();

		if (extFieldsView == null)
			return result;

		try {

			extFieldsView.updateExtensionFields();
			ArrayList<ExtFieldOT> lExtFields = extFieldsView
					.getExtensionFields();

			CommonManager manager = this.getRemote();

			if (lExtFields != null)
				if (lExtFields.size() > 0)
					result = manager.saveExtendedItemValues(lExtFields, id);

		} catch (RemoteException rEx) {
			this.logger
					.error(
							"No se encontró el servicio o hubo errores al llamar a los métodos remotos!",
							rEx);
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND, rEx));
		} catch (ExtTableException ex) {
			ex.printStackTrace();
			this.logger
					.error(
							"No se ha podido guardar el catalogo de propiedades de extension para la tabla: ",
							ex);

			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							ex.getErrCode(), ex));
		} catch (ExplicaException eEx) {
			this.logger
					.error(
							"No se ha podido guardar el catalogo de propiedades de extension para la tabla: ",
							eEx);
			result.addResultMessage(OperationResult.RESULT_ERROR, eEx
					.getResMsg());
		}

		return result;

	}
	
	protected BaseVO loadEntity(Long idEntity) throws ExplicaException {
		this.logger.debug("Loading entity: " + idEntity);
		BaseVO result = null;
		try {
			CommonManager manager = getRemote();
			if (idEntity != null && idEntity != 0) {
				result = manager.getEntity(idEntity, this.getClassEntity());
			} else {
				result = null;
			}
		} catch (ExplicaException e) {
			e.printStackTrace();
			throw e;
		} catch (RemoteException e) {
			e.printStackTrace();
			throw new ExplicaException(new ResultMessage(InterfaceErrors.ERR_RMI_NO_ACCESS, e));
		}

		return result;
	}
	
	protected List<BaseVO> loadEntities() throws ExplicaException {
		this.logger.debug("Loading entities: " + this.getClassEntity().getCanonicalName());
		List <BaseVO> result = null;
		try {
			CommonManager manager = getRemote();
			result = manager.queryEntities("", "", this.getClassEntity());
		} catch (ExplicaException e) {
			e.printStackTrace();
			throw e;
		} catch (RemoteException e) {
			e.printStackTrace();
			throw new ExplicaException(new ResultMessage(InterfaceErrors.ERR_RMI_NO_ACCESS, e));
		}

		return result;
	}

	/**
	 * 
	 * Initializes the specific components of the client
	 */
	public abstract void init_specific_components();

	/**
	 * Build the view of the extension fields. <br>
	 * It must implement only those clients who require it
	 */
	public abstract void build_extension_fields_view();

	/**
	 * Build 2 sets of SubentityOT: lSelectionSubentities and
	 * lMultiSelectionSubentities <br>
	 * These sets are used to connect the widgets with the handlers for the
	 * selection buttons and the multiseleccion panels <br>
	 * It must implement only those clients who require it
	 */
	public abstract void buildSelectionSets();

	/**
	 * 
	 * Get the widgets from the glade and stored in local variables. <br>
	 * Must be overwritten
	 */
	public abstract void getWidgets();

	@Override
	public abstract BaseVO getEntityData();

	@Override
	public abstract void setEditionMode(boolean enabled);

	/**
	 * Set the values of the widgets on the edit dialog. <br>
	 * Must be overwritten.
	 * 
	 * @param entity
	 *            BaseVO. Entity that contains the values to be displayed
	 */
	public abstract void setWidgetsValues(BaseVO entity);

	/**
	 * Validate the values of the widgets in the edit dialog. <br>
	 * Must be overwritten.
	 * 
	 * @return OperationResult. Result of the validation.
	 */
	public abstract OperationResult validateEntity();
	
	/**
	 * Returns the edition Gui instance.
	 * @return Gui, entity edition Gui.
	 */
	public Gui getEditionGui() {
		if (this.entEditView != null)
			return this.entEditView.getGui();
		else
			return null;
	}

	public void addExplicaEventListener(ExplicaEventListener l){
		if (isDetail())
			this.entityDetailView.addExplicaEventListener(l);
		else
			this.entView.addExplicaEventListener(l);
		this.getEntityDialog();
		this.entEditView.addExplicaEventListener(l);
	
	}
}
